home *** CD-ROM | disk | FTP | other *** search
- /* Grok X modifier mappings for shortcuts.
-
- Most of this code was taken from src/event-Xt.c in XEmacs 20.3-b17.
- The copyright(s) from the original XEmacs code are included below.
-
- Perpetrator: Sudish Joseph <sj@eng.mindspring.net>, Sept. 1997. */
-
- /* The event_stream interface for X11 with Xt, and/or tty frames.
- Copyright (C) 1991, 1992, 1993, 1994, 1995 Free Software Foundation, Inc.
- Copyright (C) 1995 Sun Microsystems, Inc.
- Copyright (C) 1996 Ben Wing.
-
- This file is part of XEmacs.
-
- XEmacs is free software; you can redistribute it and/or modify it
- under the terms of the GNU General Public License as published by the
- Free Software Foundation; either version 2, or (at your option) any
- later version.
-
- XEmacs is distributed in the hope that it will be useful, but WITHOUT
- ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
- for more details.
-
- You should have received a copy of the GNU General Public License
- along with XEmacs; see the file COPYING. If not, write to
- the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
- Boston, MA 02111-1307, USA. */
-
- #include "wconfig.h"
-
- #include <string.h>
- #include <X11/Xlib.h>
- #include <X11/keysym.h>
-
- #include "WUtil.h"
-
-
- extern Display *dpy;
-
- /************************************************************************/
- /* keymap handling */
- /************************************************************************/
-
- /* X bogusly doesn't define the interpretations of any bits besides
- ModControl, ModShift, and ModLock; so the Interclient Communication
- Conventions Manual says that we have to bend over backwards to figure
- out what the other modifier bits mean. According to ICCCM:
-
- - Any keycode which is assigned ModControl is a "control" key.
-
- - Any modifier bit which is assigned to a keycode which generates Meta_L
- or Meta_R is the modifier bit meaning "meta". Likewise for Super, Hyper,
- etc.
-
- - Any keypress event which contains ModControl in its state should be
- interpreted as a "control" character.
-
- - Any keypress event which contains a modifier bit in its state which is
- generated by a keycode whose corresponding keysym is Meta_L or Meta_R
- should be interpreted as a "meta" character. Likewise for Super, Hyper,
- etc.
-
- - It is illegal for a keysym to be associated with more than one modifier
- bit.
-
- This means that the only thing that emacs can reasonably interpret as a
- "meta" key is a key whose keysym is Meta_L or Meta_R, and which generates
- one of the modifier bits Mod1-Mod5.
-
- Unfortunately, many keyboards don't have Meta keys in their default
- configuration. So, if there are no Meta keys, but there are "Alt" keys,
- emacs will interpret Alt as Meta. If there are both Meta and Alt keys,
- then the Meta keys mean "Meta", and the Alt keys mean "Alt" (it used to
- mean "Symbol," but that just confused the hell out of way too many people).
-
- This works with the default configurations of the 19 keyboard-types I've
- checked.
-
- Emacs detects keyboard configurations which violate the above rules, and
- prints an error message on the standard-error-output. (Perhaps it should
- use a pop-up-window instead.)
- */
-
- static int MetaMask, HyperMask, SuperMask, AltMask, ModeMask;
-
- static const char *
- index_to_name (int indice)
- {
- switch (indice)
- {
- case ShiftMapIndex: return "ModShift";
- case LockMapIndex: return "ModLock";
- case ControlMapIndex: return "ModControl";
- case Mod1MapIndex: return "Mod1";
- case Mod2MapIndex: return "Mod2";
- case Mod3MapIndex: return "Mod3";
- case Mod4MapIndex: return "Mod4";
- case Mod5MapIndex: return "Mod5";
- default: return "???";
- }
- }
-
- static void
- x_reset_modifier_mapping (Display *display)
- {
- int modifier_index, modifier_key, column, mkpm;
- int warned_about_overlapping_modifiers = 0;
- int warned_about_predefined_modifiers = 0;
- int warned_about_duplicate_modifiers = 0;
- int meta_bit = 0;
- int hyper_bit = 0;
- int super_bit = 0;
- int alt_bit = 0;
- int mode_bit = 0;
- XModifierKeymap *x_modifier_keymap = XGetModifierMapping (display);
-
- #define modwarn(name,old,other) \
- wwarning ("%s (0x%x) generates %s, which is generated by %s.\n\n", \
- name, code, index_to_name (old), other), \
- warned_about_overlapping_modifiers = 1
-
- #define modbarf(name,other) \
- wwarning ("%s (0x%x) generates %s, which is nonsensical.\n\n", \
- name, code, other), \
- warned_about_predefined_modifiers = 1
-
- #define check_modifier(name,mask) \
- if ((1<<modifier_index) != mask) \
- wwarning ("%s (0x%x) generates %s, which is nonsensical.\n\n", \
- name, code, index_to_name (modifier_index)), \
- warned_about_predefined_modifiers = 1
-
- #define store_modifier(name,old) \
- if (old && old != modifier_index) \
- wwarning ("%s (0x%x) generates both %s and %s, which is nonsensical.\n\n",\
- name, code, index_to_name (old), \
- index_to_name (modifier_index)), \
- warned_about_duplicate_modifiers = 1; \
- if (modifier_index == ShiftMapIndex) modbarf (name,"ModShift"); \
- else if (modifier_index == LockMapIndex) modbarf (name,"ModLock"); \
- else if (modifier_index == ControlMapIndex) modbarf (name,"ModControl"); \
- else if (sym == XK_Mode_switch) \
- mode_bit = modifier_index; /* Mode_switch is special, see below... */ \
- else if (modifier_index == meta_bit && old != meta_bit) \
- modwarn (name, meta_bit, "Meta"); \
- else if (modifier_index == super_bit && old != super_bit) \
- modwarn (name, super_bit, "Super"); \
- else if (modifier_index == hyper_bit && old != hyper_bit) \
- modwarn (name, hyper_bit, "Hyper"); \
- else if (modifier_index == alt_bit && old != alt_bit) \
- modwarn (name, alt_bit, "Alt"); \
- else \
- old = modifier_index;
-
- mkpm = x_modifier_keymap->max_keypermod;
- for (modifier_index = 0; modifier_index < 8; modifier_index++)
- for (modifier_key = 0; modifier_key < mkpm; modifier_key++) {
- KeySym last_sym = 0;
- for (column = 0; column < 4; column += 2) {
- KeyCode code = x_modifier_keymap->modifiermap[modifier_index * mkpm
- + modifier_key];
- KeySym sym = (code ? XKeycodeToKeysym (display, code, column) : 0);
- if (sym == last_sym) continue;
- last_sym = sym;
- switch (sym) {
- case XK_Mode_switch:store_modifier ("Mode_switch", mode_bit); break;
- case XK_Meta_L: store_modifier ("Meta_L", meta_bit); break;
- case XK_Meta_R: store_modifier ("Meta_R", meta_bit); break;
- case XK_Super_L: store_modifier ("Super_L", super_bit); break;
- case XK_Super_R: store_modifier ("Super_R", super_bit); break;
- case XK_Hyper_L: store_modifier ("Hyper_L", hyper_bit); break;
- case XK_Hyper_R: store_modifier ("Hyper_R", hyper_bit); break;
- case XK_Alt_L: store_modifier ("Alt_L", alt_bit); break;
- case XK_Alt_R: store_modifier ("Alt_R", alt_bit); break;
- case XK_Control_L: check_modifier ("Control_L", ControlMask); break;
- case XK_Control_R: check_modifier ("Control_R", ControlMask); break;
- case XK_Shift_L: check_modifier ("Shift_L", ShiftMask); break;
- case XK_Shift_R: check_modifier ("Shift_R", ShiftMask); break;
- case XK_Shift_Lock: check_modifier ("Shift_Lock", LockMask); break;
- case XK_Caps_Lock: check_modifier ("Caps_Lock", LockMask); break;
-
- /* It probably doesn't make any sense for a modifier bit to be
- assigned to a key that is not one of the above, but OpenWindows
- assigns modifier bits to a couple of random function keys for
- no reason that I can discern, so printing a warning here would
- be annoying. */
- }
- }
- }
- #undef store_modifier
- #undef check_modifier
- #undef modwarn
- #undef modbarf
-
- /* If there was no Meta key, then try using the Alt key instead.
- If there is both a Meta key and an Alt key, then the Alt key
- is not disturbed and remains an Alt key. */
- if (! meta_bit && alt_bit)
- meta_bit = alt_bit, alt_bit = 0;
-
- /* mode_bit overrides everything, since it's processed down inside of
- XLookupString() instead of by us. If Meta and Mode_switch both
- generate the same modifier bit (which is an error), then we don't
- interpret that bit as Meta, because we can't make XLookupString()
- not interpret it as Mode_switch; and interpreting it as both would
- be totally wrong. */
- if (mode_bit)
- {
- const char *warn = 0;
- if (mode_bit == meta_bit) warn = "Meta", meta_bit = 0;
- else if (mode_bit == hyper_bit) warn = "Hyper", hyper_bit = 0;
- else if (mode_bit == super_bit) warn = "Super", super_bit = 0;
- else if (mode_bit == alt_bit) warn = "Alt", alt_bit = 0;
- if (warn)
- {
- wwarning
- ("%s is being used for both Mode_switch and %s.\n\n",
- index_to_name (mode_bit), warn),
- warned_about_overlapping_modifiers = 1;
- }
- }
-
- MetaMask = (meta_bit ? (1 << meta_bit) : 0);
- HyperMask = (hyper_bit ? (1 << hyper_bit) : 0);
- SuperMask = (super_bit ? (1 << super_bit) : 0);
- AltMask = (alt_bit ? (1 << alt_bit) : 0);
- ModeMask = (mode_bit ? (1 << mode_bit) : 0); /* unused */
-
- #if 0
- if (warned_about_overlapping_modifiers)
- wwarning ("\n"
- " Two distinct modifier keys (such as Meta and Hyper) cannot generate\n"
- " the same modifier bit, because Emacs won't be able to tell which\n"
- " modifier was actually held down when some other key is pressed. It\n"
- " won't be able to tell Meta-x and Hyper-x apart, for example. Change\n"
- " one of these keys to use some other modifier bit. If you intend for\n"
- " these keys to have the same behavior, then change them to have the\n"
- " same keysym as well as the same modifier bit.\n");
-
- if (warned_about_predefined_modifiers)
- wwarning ("\n"
- " The semantics of the modifier bits ModShift, ModLock, and ModControl\n"
- " are predefined. It does not make sense to assign ModControl to any\n"
- " keysym other than Control_L or Control_R, or to assign any modifier\n"
- " bits to the \"control\" keysyms other than ModControl. You can't\n"
- " turn a \"control\" key into a \"meta\" key (or vice versa) by simply\n"
- " assigning the key a different modifier bit. You must also make that\n"
- " key generate an appropriate keysym (Control_L, Meta_L, etc).\n");
-
- /* No need to say anything more for warned_about_duplicate_modifiers. */
-
- if (warned_about_overlapping_modifiers || warned_about_predefined_modifiers)
- wwarning ("\n"
- " The meanings of the modifier bits Mod1 through Mod5 are determined\n"
- " by the keysyms used to control those bits. Mod1 does NOT always\n"
- " mean Meta, although some non-ICCCM-compliant programs assume that.\n");
- #endif
- XFreeModifiermap(x_modifier_keymap);
- }
-
-
- int
- wXModifierFromKey(char *key)
- {
- if (strcasecmp(key, "SHIFT")==0 && ShiftMask!=0)
- return ShiftMask;
- else if (strcasecmp(key, "CONTROL")==0 && ControlMask!=0)
- return ControlMask;
- else if (strcasecmp(key, "ALT")==0 && AltMask!=0)
- return AltMask;
- else if (strcasecmp(key, "META")==0 && MetaMask!=0)
- return MetaMask;
- else if (strcasecmp(key, "SUPER")==0 && SuperMask!=0)
- return SuperMask;
- else if (strcasecmp(key, "HYPER")==0 && HyperMask!=0)
- return HyperMask;
- else if (strcasecmp(key, "MOD1")==0 && Mod1Mask!=0)
- return Mod1Mask;
- else if (strcasecmp(key, "MOD2")==0 && Mod2Mask!=0)
- return Mod2Mask;
- else if (strcasecmp(key, "MOD3")==0 && Mod3Mask!=0)
- return Mod3Mask;
- else if (strcasecmp(key, "MOD4")==0 && Mod4Mask!=0)
- return Mod4Mask;
- else if (strcasecmp(key, "MOD5")==0 && Mod5Mask!=0)
- return Mod5Mask;
- else
- return -1;
- }
-
- /* Wrapper so that we may fit the WM naming conventions, yet leave the
- original XEmacs function name in place. */
- void
- wXModifierInitialize(void)
- {
- x_reset_modifier_mapping(dpy);
- }
-